#!/usr/bin/env python
# $Id: switchinfo.py df54dec975f4 2012/09/09 20:22:40 pgurumur $
# Copyright (c) 2012 Prabhu Gurumurthy <pgurumur@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

__version__  = "$Revision: df54dec975f4 $"
__author__   = "$Author: pgurumur $"
__modified__ = "$Date: 2012-09-09 20:22:40Z $"

from __future__ import division

import optparse
import os
import sys

from venya.lib import exception
from venya.lib import cmdparser
from venya.lib import config
from venya.lib import sql
from venya.lib import stdlib
from venya.lib import ip


class switchinfo(cmdparser.GetOpt):
   option_list = (
         optparse.make_option("-s", "--site", type = "str",
            help = "List information for switches located in a site",
            dest = "site"),
         optparse.make_option("-c", "--config", type = "str",
            help = "Configuration file for netdot crendentials",
            default  = "db.cfg", dest = "config"),
   ) + cmdparser.GetOpt.option_list

   def __init__(self, **Keywords):
      super(switchinfo, self).__init__(**Keywords)
      self._count = 0
      self._fh = None
      self._cfg = None
      self._netdb = None
      self._device = None
      self._interface = None
      self._entity = None
      self._ipblock = None
      self._stp = None
      self._site = None
      self._host = []
      self._verbose = False

   def warn(self, fmt, *args):
      """
      @brief wrapper for print function using format and arguments
      @param self 'this' pointer for the class
      @param fmt format string
      @param args arguments corresponding for format
      """
      print("%s: %s" %(str(self), stdlib.sprintf(fmt, *args)))

   def GetDeviceIP(self, Id = 0):
      retval = None
      ix = [ addr[0] for addr in self._device.q.filter(
         self._device.id == int(Id)).values(self._device.snmp_target)]
      if ix:
         addr = self._ipblock.q.filter(self._ipblock.id == ix[0]).all()[0]
         address = None
         try:
            address = ip.ip(int(addr[0]), version = 4)
         except exception.IPError as err:
            self.warn(err)
         else:
            retval = address

      return retval

   def GetDeviceName(self, Id = 0):
      retval = None
      ix = [ name[0] for name in self._device.q.filter(
         self._device.id == int(Id)).values(self._device.name)]
      if ix:
         rr = self._netdb.rr
         zone = self._netdb.zone
         jy = [ (zid, name) for (zid, name) in rr.q.filter(
            rr.id == ix[0]).values(rr.zone, rr.name)]
         name = jy[0][1]
         jy = [ zoneName[0] for zoneName in zone.q.filter(
            zone.id == int(jy[0][0])).values(zone.name)]
         if name and jy:
            retval = "%s.%s" %(name, jy[0])

      return retval

   def isswitch(self, Id = 0):
      retval = False
      temp = []
      for ix in self._stp.q.filter(self._stp.device == Id).all():
         temp.append(ix)

      if len(temp):
         retval = True

      return retval

   def GetSite(self, Name = None):
      retval = 0
      if Name:
         temp = [ siteid[0] for siteid in self._site.q.filter(
            self._site.name == str(Name)).values(self._site.id)]
         if temp:
            retval = temp[0]

      return retval

   def isether(self, IfType = None):
      retval = False
      if IfType.lower().find("ethernet") >= 0:
         retval = True

      return retval

   def GetInterfaceInfo(self, Id):
      retval = []
      self._count = 0
      if self.isswitch(Id):
         for (name, oper, admin, iftype) in self._interface.q.filter(
               self._interface.device == int(Id)).values( self._interface.name,
                     self._interface.oper_status, self._interface.admin_status,
                     self._interface.type):
            self._count += 1
            if self.isether(iftype.strip()) and (
                  oper.strip() == "down") and (admin.strip() == "down"):
               retval.append(name)

      return retval

   def ifprint(self, Id, Name, IP, IfInfo, Count):
      if self.isswitch(Id):
         percent = (len(IfInfo) / Count) * 100
         print("%s(%s) usable: %d, total: %d, percent: %0.02f%%" %(
            Name, IP, len(IfInfo), Count, percent))
         if self._verbose:
            print("Available Interfaces: ")
            for ix in IfInfo:
               print("\t%s" %ix)

   def handle(self):
      (options, args) = self.parse()

      self._host = []
      try:
         self._host = args[1:]
      except IndexError as err:
         pass

      dbName = None
      device = None
      if options.config:
         try:
            self._cfg = config.Lexer(options.config)
         except exception.LexerError as err:
            self.error(err)
         else:
            dbName = self._cfg.Netdot

      if options.verbosity:
         self._verbose = bool(options.verbosity)

      try:
         if dbName:
            self._netdb = sql.mysql(dbName.dbname,
                  dbName.dbhost, dbName.dbuser, dbName.dbpass)
      except exception.SQLError as err:
         self.error(err)
      else:
         self._device = self._netdb.device
         self._contract = self._netdb.maintcontract
         self._entity = self._netdb.entity
         self._ipblock = self._netdb.ipblock
         self._interface = self._netdb.interface
         self._stp = self._netdb.stpinstance
         self._site = self._netdb.site

      site = 0
      if options.site:
         site = self.GetSite(options.site)

      if site:
         retval = None
         for (siteid, devid) in self._device.q.filter(
               self._device.site == site).values(self._device.site,
                     self._device.id):
            ipaddr = self.GetDeviceIP(devid)
            if len(self._host):
               if str(ipaddr) in self._host:
                  retval = self.GetInterfaceInfo(devid)
                  self.ifprint(devid, self.GetDeviceName(devid), ipaddr, retval,
                        self._count)
            else:
               retval =  self.GetInterfaceInfo(devid)
               self.ifprint(devid, self.GetDeviceName(devid), ipaddr, retval,
                     self._count)
      else:
         for devid in self._device.q.values(self._device.id):
            ipaddr = self.GetDeviceIP(devid[0])
            if len(self._host):
               if str(ipaddr) in self._host:
                  retval = self.GetInterfaceInfo(devid[0])
                  self.ifprint(devid[0], self.GetDeviceName(devid[0]), ipaddr,
                        retval, self._count)
            else:
               retval = self.GetInterfaceInfo(devid[0])
               self.ifprint(devid[0], self.GetDeviceName(devid[0]), ipaddr,
                     retval, self._count)

if __name__ == "__main__":
   contract = None
   try:
      info = switchinfo(version = 1.0, args = sys.argv, usage = "[ hosts... ]")
      if len(info) <= 1:
         info.printhelp()
      else:
         info.handle()
   except exception.GetOptError as err:
      print(err)
      sys.exit(1)
